import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import _ from 'lodash';
import {
  Button,
  Menu,
  Dropdown,
  Icon,
  Checkbox,
  Rate,
  Pagination,
  Spin,
  Empty,
  Popconfirm,
  message,
  Popover
} from 'antd';
import RemoveTagModal from '../remove-tag-modal';
import AddTagModal from '../add-tag-modal';
import EditOrgModal from '../edit-org-modal';
import EditAttrModal from '../edit-attr-modal';
import { actions as assetManageActions } from '../../reducer';
import SurveyBgSvg from './images/survey.svg';
import AssetTaskBgSvg from './images/asset-task-bg.svg';
import ExcelBgSvg from './images/excel-bg.svg';
import HandBgSvg from './images/hand-bg.svg';
import EmptyBgSvg from './images/empty-bg.svg';
import SwitchBgSvg from './images/switch-bg.svg';
import WordSvg from './images/word.svg';
import ExcelSvg from './images/excel.svg';
import SortUpSvg from './images/sort-up.svg';
import RiskFingerSvg from './images/risk-finger.svg';
import RiskVulSvg from './images/risk-vul.svg';
import Tag from '@components/tag';
import PropTypes from 'prop-types';
import cn from 'classnames';
import { batchDeleteAssets } from '@api/asset';
import './index.less';

const prefixCls = 'asset-list-new';

const sortKeyMap = {
  created: '创建时间',
  updated: '更新时间',
  ipLong: 'IP',
  name: '资产名称',
  risk: '风险等级'
};

class AssetList extends React.Component {
  static propTypes = {
    setState: PropTypes.func,
    isEmpty: PropTypes.func,
    currentSelectedSites: PropTypes.array,
    sort: PropTypes.object,
    currentAssetList: PropTypes.array,
    currentAssetCount: PropTypes.number,
    pagaition: PropTypes.object,
    loadingAsset: PropTypes.bool,
    assetCategoryList: PropTypes.array,
    loadAssets: PropTypes.func,
    search: PropTypes.string,
    currentAssetId: PropTypes.string,
    customAttributeList: PropTypes.array,
    organizationTree: PropTypes.array,
    loadOrganizationTree: PropTypes.func,
    loadAssetIndex: PropTypes.number,
    loadAssetListIndex: PropTypes.number,
    requestLoadAssetStatsCallback: PropTypes.func,
    history: PropTypes.object,
    modules: PropTypes.array,
    useCallbackGetCert: PropTypes.array
  };
  constructor(props) {
    super(props);
    this.state = {
      batchEditSiteAction: ''
    };

    this.debounceLoadAssets = _.debounce(this.props.loadAssets, 2000, { leading: true });
  }

  componentDidUpdate(preProps) {
    // 列表请求体改变或强制刷新时，重新请求资产
    const filterKeys = ['search', 'pagaition', 'sort', 'loadAssetListIndex'];
    const preAttributeFilter = _.omit(_.get(preProps, 'attributeFilter'), ['moreAction']);
    const currentAttributeFilter = _.omit(_.get(this.props, 'attributeFilter'), ['moreAction']);
    if (
      !_.isEqual(_.pick(preProps, filterKeys), _.pick(this.props, filterKeys)) ||
      !_.isEqual(preAttributeFilter, currentAttributeFilter)
    ) {
      this.debounceLoadAssets();
    }
  }

  checkImgPath = name => {
    let img;
    try {
      // eslint-disable-next-line
      img = (
        <img
          style={{
            width: 18,
            height: 18,
            margin: '0 0 2px 0'
          }}
          src={require(`./images/${name}.svg`)}
          alt=""
        />
      );
    } catch (err) {
      //图片不存在则使用默认的图片
      // eslint-disable-next-line
      img = (
        <img
          style={{
            width: 14,
            height: 14,
            margin: '0 3px 2px 0'
          }}
          alt=""
          src={require('./images/other.svg')}
        />
      );
    }
    return img;
  };

  renderEmptyAssetList = () => {
    const { modules } = this.props;
    const hasOneDayModule = modules.includes('1day');
    const actions = [
      {
        title: (
          <div>
            资产探测任务添加资产 <span className="suggest-recommend">推荐</span>
          </div>
        ),
        desc: '通过创建资产探测任务自动发现资产',
        action: (
          <Button
            type="primary"
            onClick={() =>
              this.props.history.push({
                pathname: '/task-list/add-task',
                state: { type: 'Zoomeye' }
              })
            }
          >
            资产探测
          </Button>
        ),
        bg: AssetTaskBgSvg
      },
      {
        title: '报表添加资产',
        desc: (
          <div>
            通过下载 excel 报表文件，批量导入资产&nbsp;
            <a className="download-excel" href="/example.xlsx">
              下载报表
            </a>
          </div>
        ),
        action: (
          <Button onClick={() => this.props.setState({ batchImportModalVisible: true })}>
            上传报表
          </Button>
        ),
        bg: ExcelBgSvg
      },
      {
        title: '手动添加资产',
        desc: '通过表单录入单个资产信息',
        action: (
          <Button onClick={() => this.props.setState({ assetSettingModalVisible: true })}>
            开始添加
          </Button>
        ),
        bg: HandBgSvg
      },
      {
        title: (
          <div>
            交换机对接添加资产 <span className="suggest-new">New</span>
          </div>
        ),
        desc: '通过配置交换机的登录信息采集 ARP 表信息获取资产',
        action: (
          <Button>
            <a href="/asset-config/switch-config">开始添加</a>
          </Button>
        ),
        bg: SwitchBgSvg
      }
    ];
    hasOneDayModule
      ? actions.splice(1, 0, {
          title: (
            <div>
              漏洞普查 <span className="suggest-recommend">推荐</span>
            </div>
          ),
          desc: '通过创建漏洞普查任务，检测目标中是否存在漏洞风险',
          action: (
            <Button
              type="primary"
              onClick={() =>
                this.props.history.push({
                  pathname: '/task-list/add-task',
                  state: { type: 'VulDetect' }
                })
              }
            >
              漏洞普查
            </Button>
          ),
          bg: SurveyBgSvg
        })
      : null;
    return (
      <div className={cn(prefixCls, `${prefixCls}-empty`)}>
        {actions.map(({ title, desc, action, bg }, index) => {
          return (
            <div key={index} className="add-asset-action">
              <img src={bg} className="bg" alt="" />
              <div className="title">{title}</div>
              <div className="desc">{desc}</div>
              <div className="action">{action}</div>
            </div>
          );
        })}
      </div>
    );
  };

  onClickMenuToOpenModal = ({ key: rawKey }) => {
    const [key, value = true] = rawKey.split('.');
    if (key === 'jumpToSwitch') {
      this.props.history.push('/asset-config/switch-config');
    }
    if (key === 'Zoomeye') {
      this.props.history.push({
        pathname: '/task-list/add-task',
        state: { type: 'Zoomeye' }
      });
    } else {
      this.props.setState({ [key]: value });
    }
  };

  onClickMenuToOpenExportModal = ({ key }) => {
    this.props.setState({ exportModalType: key });
  };

  // 批量编辑后需要重新加载的动作
  reloadAssetsAndStats = () => {
    const { setState } = this.props;
    this.props.requestLoadAssetStatsCallback();
    this.debounceLoadAssets();
    setState({ loadAssetIndex: Date.now() });
  };

  onCloseEditModal = () => {
    this.setState({ batchEditSiteAction: '' });
  };

  generateExportOverlay = () => (
    <Menu onClick={this.onClickMenuToOpenExportModal}>
      <Menu.Item key="assetDoc">
        <img src={WordSvg} alt="" /> 导出资产报告
      </Menu.Item>
      <Menu.Item key="assetForm">
        <img src={ExcelSvg} alt="" /> 导出报表
      </Menu.Item>
    </Menu>
  );

  generateAddAssetOverlay = () => (
    <Menu className={`${prefixCls}-add-site-menu`} onClick={this.onClickMenuToOpenModal}>
      <Menu.Item key="assetSettingModalVisible">单个添加(手动)</Menu.Item>
      <Menu.Item key="batchImportModalVisible">批量添加(报表)</Menu.Item>
      <Menu.Item key="Zoomeye">
        资产探测发现<span className="suggest-recommend">推荐</span>
      </Menu.Item>
      <Menu.Item key="jumpToSwitch">
        从交换机采集<span className="suggest-new">New</span>
      </Menu.Item>
    </Menu>
  );

  generateSiteOverlay = () => (
    <Menu
      onClick={({ key }) => {
        this.setState({ batchEditSiteAction: key });
      }}
    >
      <Menu.Item key="addTag">添加标签</Menu.Item>
      <Menu.Item key="removeTag">移除标签</Menu.Item>
      <Menu.Item key="editOrg">编辑所属部门</Menu.Item>
      <Menu.Item key="editAttr">编辑自定义属性</Menu.Item>
    </Menu>
  );

  renderAssetItem = asset => {
    const {
      _id: id,
      ip,
      ipv6,
      url,
      name,
      weight,
      assetCategories = [],
      tags = [],
      vulLevelCountMap,
      hasRiskFinger,
      titles
    } = asset;
    const assetName = name || [].concat(titles).join(',') || '';
    const { currentSelectedSites, setState, currentAssetId } = this.props;
    const hasVul = _.get(vulLevelCountMap, 'total', 0) > 0;
    const categoriesLen = _.get(assetCategories, 'length');
    return (
      <div
        className={cn('asset', { active: currentAssetId && currentAssetId === id })}
        onClick={() => setState({ currentAssetId: asset._id })}
      >
        <Checkbox
          indeterminate={_.some(currentSelectedSites, i => i._id === asset._id)}
          checked={_.some(currentSelectedSites, i => i._id === asset._id)}
          className="checkbox"
          onChange={checked => this.trigerCheckAsset(checked, asset)}
        />
        <div className="data">
          <div className="top">
            <div className="address">
              {/* <img className="asset-category-icon" src={SwitchIconSvg} /> */}
              {assetName && <div className="item">{assetName}</div>}
              {url && (
                <div className="item">
                  <a href={url} target="_blank" rel="noopener noreferrer">
                    {url}
                  </a>
                </div>
              )}
              <div className="item">{ipv6 ? ipv6 : ip}</div>
            </div>
            <div className="risk-weight">
              <div className="risk-wrapper">
                {(hasRiskFinger || hasVul) && (
                  <div className="risk">
                    {hasVul && <img src={RiskVulSvg} alt="" />}
                    {hasRiskFinger && <img src={RiskFingerSvg} alt="" />}
                  </div>
                )}
              </div>
              <Rate className="weight" value={weight} disabled />
            </div>
          </div>
          {_.get(tags, 'length') > 0 && (
            <div className="tags">
              {_.map(tags, ({ name, color }) => (
                <Tag key={name} value={name} color={color} />
              ))}
            </div>
          )}
          {categoriesLen > 0 && (
            <div className="categories">
              {_.map(assetCategories, ({ name }, index) => {
                return (
                  <span className="categories-name">
                    <span className="categories-icon">
                      {index <= 9 && categoriesLen > 2 ? (
                        <Popover placement="top" content={name}>
                          {this.checkImgPath(name)}
                        </Popover>
                      ) : (
                        ''
                      )}
                      {categoriesLen <= 2 ? this.checkImgPath(name) : ''}
                      <span className="categories-name">{categoriesLen <= 2 ? name : ''}</span>
                    </span>

                    {index === 9 ? '...' : ''}
                  </span>
                );
              })}
            </div>
          )}
        </div>
      </div>
    );
  };

  trigerCheckCurrentPage = e => {
    const { setState, currentSelectedSites, currentAssetList } = this.props;
    if (e.target.checked) {
      setState({
        currentSelectedSites: _.unionBy(currentSelectedSites, currentAssetList, '_id')
      });
    } else {
      setState({
        currentSelectedSites: _.differenceBy(currentSelectedSites, currentAssetList, '_id')
      });
    }
  };

  trigerCheckAsset = (e, asset) => {
    const { setState, currentSelectedSites } = this.props;
    if (e.target.checked) {
      setState({
        currentSelectedSites: _.unionBy(currentSelectedSites, [asset], '_id')
      });
    } else {
      setState({
        currentSelectedSites: _.differenceBy(currentSelectedSites, [asset], '_id')
      });
    }
  };

  onPaginationChange = (page, pageSize) => {
    const { setState } = this.props;
    setState({ pagaition: { page, pageSize } });
  };

  deleteSelectedSites = () => {
    const {
      currentSelectedSites,
      requestLoadAssetStatsCallback,
      loadAssets,
      setState,
      useCallbackGetCert
    } = this.props;
    const selectedSiteIds = _.map(currentSelectedSites, '_id');
    batchDeleteAssets(selectedSiteIds)
      .then(() => {
        message.success('删除资产成功');
        loadAssets();
        requestLoadAssetStatsCallback();
        useCallbackGetCert();
        setState({ currentSelectedSites: [] });
      })
      .catch(() => {
        message.error('删除资产失败');
      });
  };

  render() {
    if (this.props.isEmpty) {
      return this.renderEmptyAssetList();
    }
    const { batchEditSiteAction } = this.state;
    const {
      currentSelectedSites,
      sort,
      setState,
      currentAssetCount,
      currentAssetList,
      pagaition,
      loadingAsset,
      customAttributeList,
      organizationTree,
      loadOrganizationTree,
      modules
    } = this.props;
    const selectedSiteIds = _.map(currentSelectedSites, '_id');
    const hasOneDayModule = modules.includes('1day');

    const dispatchChangeSortOverlay = (
      <Menu onClick={({ key: by }) => setState({ sort: Object.assign({}, sort, { by }) })}>
        {Object.keys(sortKeyMap)
          .filter(i => hasOneDayModule || i !== 'risk')
          .map(key => {
            return <Menu.Item key={key}>{sortKeyMap[key]}</Menu.Item>;
          })}
      </Menu>
    );
    const checkedCurrentPage =
      !_.isEmpty(currentAssetList) &&
      _.isEmpty(_.differenceBy(currentAssetList, currentSelectedSites, '_id'));

    const siteSelected = _.get(currentSelectedSites, 'length') > 0;

    return (
      <div className={cn(prefixCls, `${prefixCls}-not-empty`)}>
        <div className="opts">
          <Button
            className="task-btn"
            type="primary"
            onClick={() =>
              this.props.history.push({
                pathname: '/task-list/add-task',
                state: { type: 'Zoomeye', currentSelectedSites }
              })
            }
          >
            资产探测
          </Button>
          {hasOneDayModule && (
            <Button
              className="task-btn"
              type="primary"
              onClick={() =>
                this.props.history.push({
                  pathname: '/task-list/add-task',
                  state: { type: 'VulDetect', currentSelectedSites }
                })
              }
            >
              漏洞普查
            </Button>
          )}
          <Dropdown className="export-btn" overlay={this.generateExportOverlay}>
            <Button>
              <Icon type="download" />
              导出
            </Button>
          </Dropdown>
          <Popconfirm
            disabled={!siteSelected}
            title="确定删除吗"
            onConfirm={this.deleteSelectedSites}
          >
            <Button type="danger" className="delete-btn" disabled={!siteSelected}>
              删除
            </Button>
          </Popconfirm>

          {siteSelected ? (
            <Dropdown overlay={this.generateSiteOverlay}>
              <Button className="edit-btn">编辑</Button>
            </Dropdown>
          ) : (
            <Button disabled className="edit-btn">
              编辑
            </Button>
          )}

          <Dropdown className="add-asset-btn" overlay={this.generateAddAssetOverlay}>
            <Button>
              <Icon type="plus-circle" />
              添加
            </Button>
          </Dropdown>
        </div>
        <div className="select-sort">
          <Checkbox
            indeterminate={checkedCurrentPage}
            className="check-current-page"
            checked={checkedCurrentPage}
            onChange={this.trigerCheckCurrentPage}
          >
            选择本页
          </Checkbox>
          <Dropdown
            className={`${prefixCls}-sort`}
            overlayClassName={`${prefixCls}-sort-dropdown`}
            overlay={dispatchChangeSortOverlay}
          >
            <span>
              {sortKeyMap[sort.by]}&nbsp;
              <img
                className={cn('sort-array', sort.direction === 1 ? 'up' : 'down')}
                src={SortUpSvg}
                alt=""
                onClick={e => {
                  e.stopPropagation();
                  setState({ sort: Object.assign({}, sort, { direction: -sort.direction }) });
                }}
              />
              <Icon type="down" />
            </span>
          </Dropdown>
        </div>
        <div className="assets-container">
          <Spin spinning={loadingAsset}>
            {_.isEmpty(currentAssetList) ? (
              <Empty className="empty" image={EmptyBgSvg} description="诶，好像什么都没有" />
            ) : (
              currentAssetList.map(this.renderAssetItem)
            )}
          </Spin>
          <div className="pagination-wrapper">
            <Pagination
              className="pagination"
              size="small"
              current={pagaition.page}
              pageSize={pagaition.pageSize}
              onChange={this.onPaginationChange}
              onShowSizeChange={this.onPaginationChange}
              total={currentAssetCount}
              showSizeChanger
              showQuickJumper
              showLessItems
              showTotal={total => `共 ${total} 条`}
              pageSizeOptions={['10', '20', '30', '50', '100']}
            />
          </div>
        </div>
        <RemoveTagModal
          visible={batchEditSiteAction === 'removeTag'}
          siteIds={selectedSiteIds}
          onClose={this.onCloseEditModal}
          sites={currentSelectedSites}
          loadAssets={this.reloadAssetsAndStats}
        />
        <AddTagModal
          visible={batchEditSiteAction === 'addTag'}
          siteIds={selectedSiteIds}
          onClose={this.onCloseEditModal}
          loadAssets={this.reloadAssetsAndStats}
        />
        <EditOrgModal
          visible={batchEditSiteAction === 'editOrg'}
          siteIds={selectedSiteIds}
          onClose={this.onCloseEditModal}
          onOrgPopupVisibleChange={visible => visible && loadOrganizationTree()}
          sites={currentSelectedSites}
          loadAssets={this.reloadAssetsAndStats}
          organizationTree={organizationTree}
        />
        <EditAttrModal
          visible={batchEditSiteAction === 'editAttr'}
          siteIds={selectedSiteIds}
          onClose={this.onCloseEditModal}
          customList={customAttributeList}
          loadAssets={this.reloadAssetsAndStats}
        />
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    tags: _.get(state, 'tag.tags', []),
    attributeFilter: _.get(state, 'assetManage.attributeFilter', {}),
    customAttributeList: _.get(state, 'assetManage.customAttributeList', []),
    organizationTree: _.get(state, 'assetManage.organizationTree', []),
    assetCategoryList: _.get(state, 'assetManage.assetCategoryList', []),
    assetCategoryTree: _.get(state, 'assetManage.assetCategoryTree', []),
    currentAssetList: _.get(state, 'assetManage.currentAssetList', []),
    currentAssetCount: _.get(state, 'assetManage.currentAssetCount', []),
    currentAssetId: _.get(state, 'assetManage.currentAssetId', {}),
    pagaition: _.get(state, 'assetManage.pagaition', []),
    areaList: _.get(state, 'assetManage.areaList', []),
    siteAttributeStats: _.get(state, 'assetManage.siteAttributeStats', []),
    isEmpty: !_.get(state, 'assetManage.existSite'),
    currentSelectedSites: _.get(state, 'assetManage.currentSelectedSites', []),
    sort: _.get(state, 'assetManage.sort', { by: 'createdAt', direction: -1 }),
    loadingAsset: _.get(state, 'assetManage.loadingAsset', -1),
    search: _.get(state, 'assetManage.search', ''),
    loadAssetListIndex: _.get(state, 'assetManage.loadAssetListIndex', 0),
    modules: _.get(state, 'auth.cert.modules', [])
  };
};

const mapDispatchToProps = dispatch => {
  return {
    ...bindActionCreators(assetManageActions, dispatch)
  };
};
export default withRouter(
  connect(
    mapStateToProps,
    mapDispatchToProps
  )(AssetList)
);
